﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using AcademicPlanner.Framework.Helpers;
using AcademicPlanner.Framework.Libraries.Mvc;

namespace AcademicPlanner.Presentation
{
	/// <summary>
	/// JsonResultData represents data that gets serialized to json and sent to
	/// the browser as a response to an ajax request.
	/// </summary>
	/// <version>1.0</version>
	/// <since>1.0</since>
	struct JsonResultData
	{
		/// <summary>
		/// The html summary of input errors if any.
		/// </summary>
		/// <version>1.0</version>
		/// <since>1.0</since>
		public string errors;

		/// <summary>
		/// Whether to reload the page or not.
		/// </summary>
		/// <version>1.0</version>
		/// <since>1.0</since>
		public bool reload;

		/// <summary>
		/// Where to redirect to if necessary.
		/// </summary>
		/// <version>1.0</version>
		/// <since>1.0</since>
		public string redirect;
	}


	/// <summary>
	/// Controller is the base class for all MVC controllers in the AcademicPlanner application.
	/// </summary>
	/// <version>1.0</version>
	/// <since>1.0</since>
    public abstract class Controller : System.Web.Mvc.Controller
    {
		private FormSubmission post;


		/// <summary>
		/// Gets the top level <c>FormSubmission</c>.
		/// </summary>
		/// <version>1.0</version>
		/// <since>1.0</since>
		public FormSubmission Post { get { return post; } }


		/// <summary>
		/// Gets the instance of the <c>AcademicPlannerWebApp</c> this Controller is
		/// executing under.
		/// </summary>
		/// <seealso cref="P:AcademicPlannerWebApp.Current"/>
		/// <version>1.0</version>
		/// <since>1.0</since>
		public AcademicPlannerWebApp Application
		{
			get { return AcademicPlannerWebApp.Current; }
		}


		/// <summary>
		/// Handles the pre-execution of an action method of this Controller.
		/// This method resumes the current session, registers the view engine and builds
		/// the top level <c>FormSubmission</c> using the POST data in the <see cref="P:Request"/>.
		/// It also verifies the anti-forgery token in case of a POST and resets it in case of
		/// a GET to a new token.
		/// </summary>
		/// <param name="filterContext">The filter context</param>
		/// <exception cref="T:System.Web.Mvc.HttpAntiForgeryException">
		/// Thrown if the top level <c>FormSubmission</c>'s <see cref="P:FormSubmission.Signature"/>
		/// does not match the signature token last stored in the session.
		/// </exception>
		/// <seealso cref="M:AcademicPlanner.Framework.Helpers.SessionHelper.Resume"/>
		/// <seealso cref="T:AcademicPlanner.Framework.Libraries.Mvc.LocalizedSkinnedViewEngine"/>
		/// <seealso cref="M:AcademicPlanner.Framework.Helpers.SessionHelper.GetPostSignatureToken"/>
		/// <seealso cref="M:AcademicPlanner.Framework.Helpers.SessionHelper.ResetPostSignatureToken"/>
		/// <seealso cref="M:AcademicPlanner.Framework.Helpers.SecurityHelper.RandomHash"/>
		/// <version>1.0</version>
		/// <since>1.0</since>
		protected override void OnActionExecuting(ActionExecutingContext filterContext)
		{
			base.OnActionExecuting(filterContext);

			SessionHelper.Resume(Session);
			RegisterViewEngine();

			if (Request.Form.Count > 0)
			{
				post = new FormSubmission(Request.Form);
				if (!post.Signature.Equals(SessionHelper.GetPostSignatureToken()))
				{
					throw new HttpAntiForgeryException(Tr("The request signature is invalid!" +
							" This request may be forged. Please browse to the required page" +
							" before performing an action."));
				}
			}
			else
				SessionHelper.ResetPostSignatureToken(SecurityHelper.RandomHash());
		}

		private void RegisterViewEngine()
		{
			ViewEngines.Engines.RemoveAt(0);
			ViewEngines.Engines.Add(new LocalizedSkinnedViewEngine(
					(string)SessionHelper.Get("Presentation.Skin"), SessionHelper.GetUserCulture()));
		}

		/// <summary>
		/// Translates a string message from the application's source language to its current
		/// target language read from the session. This method is a convenience wrapper of
		/// <see cref="M:AcademicPlanner.Framework.Helpers.TranslationHelper.Translate"/> 
		/// for <code>Controller</code> objects.
		/// </summary>
		/// <param name="pText">The message to translate.</param>
		/// <returns>The translated message.</returns>
		/// <seealso cref="M:AcademicPlanner.Framework.Helpers.TranslationHelper.Translate"/>
		/// <version>1.0</version>
		/// <since>1.0</since>
		protected static string Tr(string pText)
		{
			return TranslationHelper.Translate(pText, "Presentation");
		}
    }
}
